package com.zzyl.nursing.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huaweicloud.sdk.iotda.v5.IoTDAClient;
import com.huaweicloud.sdk.iotda.v5.model.ServiceProperty;
import com.huaweicloud.sdk.iotda.v5.model.ShowProductRequest;
import com.huaweicloud.sdk.iotda.v5.model.ShowProductResponse;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.common.utils.NicknameUtil;
import com.zzyl.common.utils.StringUtils;
import com.zzyl.common.utils.UserThreadLocal;
import com.zzyl.framework.web.service.TokenService;
import com.zzyl.nursing.domain.*;
import com.zzyl.nursing.dto.MemberDeviceDataDto;
import com.zzyl.nursing.dto.DevicePropertyDto;
import com.zzyl.nursing.dto.UserDto;
import com.zzyl.nursing.dto.UserLoginRequestDto;
import com.zzyl.nursing.mapper.*;
import com.zzyl.nursing.service.IFamilyMemberService;
import com.zzyl.nursing.service.WechatService;
import com.zzyl.nursing.vo.member.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 老人家属Service业务层处理
 *
 * @author alexis
 * @date 2025-06-03
 */
@Service
public class FamilyMemberServiceImpl extends ServiceImpl<FamilyMemberMapper, FamilyMember> implements IFamilyMemberService {

    @Autowired
    private WechatService wechatService;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private ElderMapper elderMapper;

    @Autowired
    private ContractMapper contractMapper;

    @Autowired
    private FamilyMemberElderMapper familyMemberElderMapper;

    @Autowired
    private BedMapper bedMapper;

    @Autowired
    private RoomMapper roomMapper;

    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private DeviceDataMapper deviceDataMapper;

    @Autowired
    private IoTDAClient iotClient;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 微信小程序登录
     *
     * @param userLoginRequestDto 用户登录信息
     * @return 登录信息
     */
    @Override
    public LoginVo login(UserLoginRequestDto userLoginRequestDto) {
        // 1.获取openid
        String openid = wechatService.getOpenid(userLoginRequestDto.getCode());

        // 2.根据openid查询用户信息
        FamilyMember familyMember = lambdaQuery().eq(FamilyMember::getOpenId, openid).one();

        // 3.如果用户为空，将openid设置到对象中
        if (ObjectUtil.isEmpty(familyMember)) {
            familyMember = new FamilyMember();
            familyMember.setOpenId(openid);
        }

        // 4.获取用户手机号
        String phone = wechatService.getPhone(userLoginRequestDto.getPhoneCode());
        familyMember.setPhone(phone);

        // 5.保存或修改用户
        insertOrUpdate(familyMember);

        // 6.将用户id存入token
        Map<String, Object> claims = new HashMap<>();
        claims.put("userId", familyMember.getId());
        claims.put("nickName", familyMember.getName());

        String token = tokenService.createToken(claims);
        LoginVo loginVo = new LoginVo();
        loginVo.setToken(token);
        loginVo.setNickName(familyMember.getName());

        return loginVo;
    }

    /**
     * 保存或修改用户信息
     *
     * @param familyMember 用户信息
     */
    private void insertOrUpdate(FamilyMember familyMember) {
        if (ObjectUtil.isEmpty(familyMember.getId())) {
            String nickName =
                    NicknameUtil.generateSafeNickname(4) + StringUtils.substring(familyMember.getPhone(), 7);
            familyMember.setName(nickName);
            save(familyMember);
        } else {
            updateById(familyMember);
        }
    }

    /**
     * 绑定家人
     */
    @Override
    public void add(UserDto userDto) {
        // 1.判断是否登录小程序
        // 获取用户信息
        Long userId = UserThreadLocal.getUserId();
        if (ObjectUtil.isEmpty(userId)) {
            throw new BaseException("请先登录小程序");
        }

        // 2.小程序端输入信息绑定
        // 3.查看信息是否为空
        if (ObjectUtil.isEmpty(userDto)) {
            throw new BaseException("绑定内容不能为空");
        }

        // 4.身份验证，家人姓名和身份证号必须是养老院入住的老人
        Elder elder = elderMapper.selectOne(new LambdaQueryWrapper<Elder>()
                                                    .eq(Elder::getIdCardNo, userDto.getIdCard())
                                                    .eq(Elder::getName, userDto.getName())
                                                    .eq(Elder::getStatus, 1)
                                           );
        if (ObjectUtil.isEmpty(elder)) {
            throw new BaseException("老人不存在");
        }

        // 5.判断是否签订合同
        // 根据老人id查询合同信息
        Contract contract = contractMapper.selectOne(new LambdaQueryWrapper<Contract>()
                                                             .eq(Contract::getElderId, elder.getId())
                                                             .eq(Contract::getStatus, 1)
                                                    );
        if (ObjectUtil.isEmpty(contract)) {
            throw new BaseException("未查询到合同信息，老人不存在");
        }

        // 6.判断是否绑定过此家人
        Long count = familyMemberElderMapper.selectCount(
                new LambdaQueryWrapper<FamilyMemberElder>().eq(FamilyMemberElder::getFamilyMemberId, userId)
                                                           .eq(FamilyMemberElder::getElderId, elder.getId()));
        if (count > 0) {
            throw new BaseException("此家人已绑定过此老人");
        }

        // 7.绑定成功，保存信息
        FamilyMemberElder familyMemberElder = new FamilyMemberElder();
        familyMemberElder.setElderId(elder.getId());
        familyMemberElder.setFamilyMemberId(userId);
        familyMemberElder.setRemark(userDto.getRemark());
        familyMemberElderMapper.insert(familyMemberElder);
    }

    /**
     * 获取家人信息
     */
    @Override
    public List<UserVo> my() {
        // 1.获取当前登录用户id
        Long userId = UserThreadLocal.getUserId();
        if (ObjectUtil.isEmpty(userId)) {
            throw new BaseException("用户未登录");
        }

        // 2.根据用户id查询家人信息
        List<FamilyMemberElder> familyMemberElders = familyMemberElderMapper.selectList(
                new LambdaQueryWrapper<FamilyMemberElder>().eq(FamilyMemberElder::getFamilyMemberId, userId));

        List<UserVo> userVos = new ArrayList<>();
        if (ObjectUtil.isNotEmpty(familyMemberElders)) {
            // 收集所有老人ID
            List<Long> elderIds = familyMemberElders.stream()
                                                    .map(FamilyMemberElder::getElderId)
                                                    .collect(Collectors.toList());

            // 批量查询老人信息并构建Map
            Map<Long, String> elderMap = elderMapper.selectBatchIds(elderIds)
                                                    .stream()
                                                    .collect(Collectors.toMap(Elder::getId, Elder::getName));

            // 转换为UserVo
            familyMemberElders.forEach(fme -> {
                UserVo userVo = BeanUtil.copyProperties(fme, UserVo.class);
                String name = elderMap.get(fme.getElderId());
                if (name != null) {
                    userVo.setElderName(name);
                }
                userVos.add(userVo);
            });
        }
        // 3.返回
        return userVos;
    }

    /**
     * 获取家人列表简单写法
     *
     * @return 家人列表
     */
    @Override
    public List<UserVo> getUserVoList() {
        Long userId = UserThreadLocal.getUserId();
        return familyMemberElderMapper.getUserVoList(userId);
    }

    /**
     * 获取家人列表(分页）
     *
     * @return 家人列表
     */
    @Override
    public List<MemberVo> listByPage() {
        List<MemberVo> memberVoList = new ArrayList<>();

        // 1.获取当前登录用户id
        Long userId = UserThreadLocal.getUserId();
        if (ObjectUtil.isEmpty(userId)) {
            throw new BaseException("用户未登录");
        }

        // 2.根据用户id查询家人信息
        List<FamilyMemberElder> familyMemberElders = familyMemberElderMapper.selectList(
                new LambdaQueryWrapper<FamilyMemberElder>().eq(FamilyMemberElder::getFamilyMemberId, userId));
        if (ObjectUtil.isEmpty(familyMemberElders)) {
            // 没有家人，返回空列表
            return memberVoList;
        }

        familyMemberElders.forEach(fme -> {
            MemberVo memberVo = new MemberVo();
            memberVo.setMid(fme.getId().toString());
            memberVo.setMremark(fme.getRemark());
            memberVo.setElderId(fme.getElderId().toString());

            // 获取老人信息
            Elder elder = elderMapper.selectOne(new LambdaQueryWrapper<Elder>().eq(Elder::getId, fme.getElderId()));
            memberVo.setName(elder.getName());
            memberVo.setImage(elder.getImage());
            memberVo.setBedNumber(elder.getBedNumber());

            // 根据床号获取房间id,再根据房间id获取房间类型名称
            Long roomId = bedMapper.selectById(elder.getBedId()).getRoomId();
            memberVo.setTypeName(roomMapper.selectById(roomId).getTypeName());

            // 获取IoT设备信息
            Device device = deviceMapper.selectOne(new LambdaQueryWrapper<Device>().eq(
                    Device::getBindingLocation,
                    elder.getId()
                                                                                      ));
            memberVo.setIotId(device.getIotId());
            memberVo.setDeviceName(device.getDeviceName());
            memberVo.setProductKey(device.getProductKey());

            memberVoList.add(memberVo);
        });
        return memberVoList;
    }

    @Override
    public List<MemberVo> listByPage2() {
        return familyMemberElderMapper.listByPage();
    }

    /**
     * 查询家人健康数据
     *
     * @return 设备属性状态列表
     */
    @Override
    public PropertyStatusInfoVoList queryDevicePropertyStatus(DevicePropertyDto devicePropertyDto) {
        // 1.根据设备名称和产品key查询设备信息
        Device device = deviceMapper.selectOne(
                new LambdaQueryWrapper<Device>().eq(Device::getDeviceName, devicePropertyDto.getDeviceName())
                                                .eq(Device::getProductKey, devicePropertyDto.getProductKey()));

        if (ObjectUtil.isEmpty(device)) {
            throw new BaseException("设备不存在");
        }

        // 2.获取设备的数据
        // 2.1 获取设备数据
        String deviceDataStr = (String) redisTemplate.opsForHash()
                                                     .get(CacheConstants.IOT_DEVICE_LAST_DATA, device.getIotId());
        List<DeviceData> deviceDataList = JSONUtil.toList(deviceDataStr, DeviceData.class);
        if (CollUtil.isEmpty(deviceDataList)) {
            return (PropertyStatusInfoVoList) Collections.emptyList();
        }

        // 2.2 获取设备属性
        ShowProductRequest request = new ShowProductRequest();
        request.setProductId(device.getProductKey());
        ShowProductResponse response = null;
        try {
            response = iotClient.showProduct(request);
        }
        catch (Exception e) {
            throw new BaseException("查询产品详情失败！");
        }
        List<ServiceProperty> properties = response.getServiceCapabilities().get(0).getProperties();
        if (CollUtil.isEmpty(properties)) {
            return (PropertyStatusInfoVoList) Collections.emptyList();
        }

        // 3.组装并返回结果
        List<PropertyStatusInfo> propertyStatusInfoList = new ArrayList<>();
        properties.forEach(property -> {
            PropertyStatusInfo propertyStatusInfo = new PropertyStatusInfo();
            propertyStatusInfo.setDataType(property.getDataType());
            propertyStatusInfo.setIdentifier(property.getPropertyName());
            propertyStatusInfo.setName(property.getDescription());
            propertyStatusInfo.setUnit(property.getUnit());

            deviceDataList.forEach(deviceData -> {
                if (propertyStatusInfo.getIdentifier().equals(deviceData.getFunctionId())) {
                    // 将字符串转为Double
                    double value = Double.parseDouble(deviceData.getDataValue());
                    // 使用String.format格式化保留一位小数
                    String formattedValue = String.format("%.1f", value);
                    propertyStatusInfo.setValue(formattedValue);

                    // 将上报时间转为时间戳
                    propertyStatusInfo.setTime(
                            String.valueOf(deviceData.getAlarmTime().toInstant(ZoneOffset.of("+8")).toEpochMilli()));
                }
            });

            propertyStatusInfoList.add(propertyStatusInfo);
        });

        System.out.println(propertyStatusInfoList);

        PropertyStatusInfoVoList propertyStatusInfoVoList = new PropertyStatusInfoVoList();
        PropertyStatusInfoVo propertyStatusInfoVo = new PropertyStatusInfoVo();
        propertyStatusInfoVo.setPropertyStatusInfo(propertyStatusInfoList);
        propertyStatusInfoVoList.setList(propertyStatusInfoVo);
        return propertyStatusInfoVoList;
    }

    /**
     * 按天查询指标数据
     *
     * @return 指标数据
     */
    @Override
    public List<Map<String, Double>> queryDeviceDataListByDay(MemberDeviceDataDto memberDeviceDataDto) {
        // 1.将开始时间戳和结束时间戳转为LocalDateTime
        LocalDateTime startTime = LocalDateTimeUtil.of(memberDeviceDataDto.getStartTime());
        LocalDateTime endTime = LocalDateTimeUtil.of(memberDeviceDataDto.getEndTime());

        // 2.查询设备数据并返回
        return deviceDataMapper.queryDeviceDataListByDay(
                memberDeviceDataDto.getIotId(),
                memberDeviceDataDto.getFunctionId(),
                startTime,
                endTime
                                                        );
    }

    /**
     * 按周查询指标数据
     *
     * @return 指标数据
     */
    @Override
    public List<Map<String, Double>> queryDeviceDataListByWeek(MemberDeviceDataDto memberDeviceDataDto) {
        // 1.将开始时间戳和结束时间戳转为LocalDateTime
        LocalDateTime startTime = LocalDateTimeUtil.of(memberDeviceDataDto.getStartTime());
        LocalDateTime endTime = LocalDateTimeUtil.of(memberDeviceDataDto.getEndTime());

        // 2.查询设备数据并返回
        return deviceDataMapper.queryDeviceDataListByWeek(
                memberDeviceDataDto.getIotId(),
                memberDeviceDataDto.getFunctionId(),
                startTime,
                endTime
                                                         );
    }
}
